package com.onlineMIS.ORM.DAO.headQ.finance;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.onlineMIS.ORM.DAO.BaseDAO;
import com.onlineMIS.ORM.DAO.headQ.barCodeGentor.HeadQEntityTagDaoImpl;
import com.onlineMIS.ORM.DAO.headQ.custMgmt.HeadQCustDaoImpl;
import com.onlineMIS.ORM.entity.base.BaseOrder;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadQTag;
import com.onlineMIS.ORM.entity.headQ.barcodeGentor.HeadqEntityTag;
import com.onlineMIS.ORM.entity.headQ.custMgmt.HeadQCust;
import com.onlineMIS.ORM.entity.headQ.finance.ChainFinanceTrace;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBill;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillFlowDetailsVO;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceBillItem;
import com.onlineMIS.ORM.entity.headQ.finance.FinanceCategory;
import com.onlineMIS.ORM.entity.headQ.finance.FinancePrestoreInfoVO;
import com.onlineMIS.ORM.entity.headQ.report.HeadQDealingsReportDTO;
import com.onlineMIS.ORM.entity.headQ.report.HeadQDealingsReportVO;
import com.onlineMIS.ORM.entity.headQ.supplier.finance.CustFinanceSummaryItem;
import com.onlineMIS.ORM.entity.headQ.supplier.finance.SupplierAcctFlow;
import com.onlineMIS.ORM.entity.headQ.supplier.finance.SupplierFinanceTrace;
import com.onlineMIS.action.headQ.finance.FinanceActionFormBean;
import com.onlineMIS.action.headQ.report.HeadQReportFormBean;
import com.onlineMIS.common.Common_util;
import com.onlineMIS.common.DateUtils;
import com.onlineMIS.filter.SystemParm;

@Repository
public class FinanceBillImpl extends BaseDAO<FinanceBill> {
	
	@Autowired
	private ChainFinanceTraceImpl chainFinanceTraceImpl;
	@Autowired
	private FinanceCategoryImpl financeCategoryImpl;
	
	@Autowired
	private HeadQCustDaoImpl headQCustDaoImpl;
	
	public void initialize(FinanceBill financeBill){
	      this.getHibernateTemplate().initialize(financeBill.getFinanceBillItemSet());
	}

	/**
	 * 根据客户查询账目客户账目流水
	 * 
	 * @param formBean
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public List<CustFinanceSummaryItem> selectFinanceReport(FinanceActionFormBean formBean, Date startDate,
			Date endDate) {
		List<CustFinanceSummaryItem> items = new ArrayList<CustFinanceSummaryItem>();
		List<Object> list = new ArrayList<Object>();
		FinanceBill financeBill = new FinanceBill();
		// 预存款合计充值金额
		String hql = "SELECT a.id,a.type,a.billDate,c.name, b.financeCategory.itemName, b.total,a.creatorHq.user_name,a.createDate,a.status  from FinanceBill a, FinanceBillItem b ,HeadQCust c,UserInfor d where a.id = b.financeBill.id and a.cust.id = c.id and a.creatorHq.user_id = d.user_id and  b.total !=0  ";

		if (formBean.getHeadQCust().getId() != Common_util.ALL_RECORD) {
			hql += "and a.cust.id = ?";
			list.add(formBean.getHeadQCust().getId());
		}
		hql += "and a.billDate between ? and ?";
		list.add(Common_util.formStartDate(startDate));
		list.add(Common_util.formEndDate(endDate));

		List<Object> results = this.executeHQLSelect(hql, list.toArray(), null, true);

		if (results != null && results.size() > 0) {
			for (Object record : results ){
				Object[] records = (Object[])record;
				Integer financeBillId = Common_util.getInt(records[0]);
				Integer financeBillType = Common_util.getInt(records[1]);
				String billDate =  Common_util.dateFormat.format(Common_util.getDate(records[2]));
				String custName = Common_util.getString(records[3]);
				String categoryName = Common_util.getString(records[4]);
				double total = Common_util.getDouble(records[5]);
				String createBy = Common_util.getString(records[6]);
				String createTime = Common_util.dateFormat_f.format(Common_util.getTimestampDate(records[7]));
				Integer status = Common_util.getInt(records[8]);
				
				String financeBillTypes = financeBill.getTypeHQMap().get(financeBillType);
				CustFinanceSummaryItem item = new CustFinanceSummaryItem();
				BaseOrder baseOrder = new BaseOrder();
				if (financeBillType == FinanceBill.FINANCE_INCOME_HQ
						|| financeBillType == FinanceBill.FINANCE_INCREASE_HQ
						|| financeBillType == FinanceBill.FINANCE_PREINCOME_HQ) {
					
					item = new CustFinanceSummaryItem(financeBillId, financeBillTypes,billDate, custName, categoryName,status,baseOrder.getStatusMap().get(status), 0,
							total,createBy,createTime);
				} else {
					item = new CustFinanceSummaryItem(financeBillId, financeBillTypes,billDate, custName, categoryName,status,baseOrder.getStatusMap().get(status), 0,
							total,createBy,createTime);
				}
				items.add(item);
			}

		}

		return items;
	}

	
	/**
	 * 根据类型查询金额合计
	 * @param type
	 * @param date
	 * @return
	 */
	public Double selectPrestore(int type) {
		DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
		criteria.add(Restrictions.eq("status", BaseOrder.STATUS_COMPLETE));
		criteria.add(Restrictions.eq("type", type));

		criteria.setProjection(Projections.sum("invoiceTotal"));				
		List<Object> result = getByCriteriaProjection(criteria, true);
        return Common_util.getProjectionDoubleValue(result);
	}

	public List<Integer> selectBills(Date startDate, Date endDate) {
		List<Integer> billIds = new ArrayList<Integer>();
		DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
		criteria.add(Restrictions.eq("status", BaseOrder.STATUS_COMPLETE));
		criteria.add(Restrictions.or(Restrictions.eq("type", FinanceBill.FINANCE_PREINCOME_HQ),Restrictions.eq("type", FinanceBill.FINANCE_PREINCOME_SPEND_HQ)));
		criteria.add(Restrictions.between("billDate", Common_util.formStartDate(startDate), Common_util.formEndDate(endDate)));
		List<FinanceBill> bills = getByCritera(criteria, true);
		if (bills.size() != 0) {
			for (FinanceBill financeBill : bills) {
				billIds.add(financeBill.getId());
			}
		}
		return billIds;
	}
	
	@Autowired
	private HeadQEntityTagDaoImpl headQEntityTagDaoImpl;

	/**
	 * 预存金流水明细查询
	 * @param startDate
	 * @param endDate
	 * @return
	 * @throws ParseException 
	 */
	public List<FinanceBillFlowDetailsVO> selectFlow(Date startDate, Date endDate,FinanceCategory category) throws ParseException {
		List<FinanceBillFlowDetailsVO> fDetailsVOs  = new ArrayList<FinanceBillFlowDetailsVO>();
		DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
		criteria.add(Restrictions.eq("status", BaseOrder.STATUS_COMPLETE));
		criteria.add(Restrictions.or(Restrictions.eq("type", FinanceBill.FINANCE_PREINCOME_HQ),Restrictions.eq("type", FinanceBill.FINANCE_PREINCOME_SPEND_HQ)));
		Date preDate = null;
		int belongTo2 = category.getBelongTo2();
		int tagId = 0;
		//判断开始时间是否在清账日期前，true:把开始时间替换为清账日期，false: 正常放startDate(千禧预存金需要判断，禧乐仓预存金不需要）
		if (belongTo2 == FinanceCategory.BELONG_TO_QX) {
			preDate = SystemParm.getPrepayFlowDate();
			tagId = HeadQTag.HEADQ_QX_CUST_TAG_ID;
			criteria.add(Restrictions.between("billDate", preDate, Common_util.formEndDate(endDate)));
		}else {
			tagId = HeadQTag.HEADQ_XLC_CUST_TAG_ID;
			criteria.add(Restrictions.between("billDate", Common_util.formStartDate(startDate), Common_util.formEndDate(endDate)));
		}
		
		List<FinanceBill> bills = getByCritera(criteria, true);
		
		// 第一行 startTime之前的sum
		FinanceBillFlowDetailsVO fDetailsVO = new FinanceBillFlowDetailsVO();
		fDetailsVO.setBillDateS(startDate);
		//首行余额 = startDate之前的预存金合计 + 所有客户期初预存金合计	
		double sum = 0;
		//千禧预存金存在清账日期，禧乐仓预存金不存在清账日期
		if (belongTo2 == FinanceCategory.BELONG_TO_QX) {
			preDate = SystemParm.getPrepayFlowDate();
			 sum = chainFinanceTraceImpl.getFirstPrepayAmount(Common_util.dateFormat.format(DateUtils.getDay(startDate, -1))) + headQCustDaoImpl.selectPbAmount(belongTo2);
		}else if (belongTo2 == FinanceCategory.BELONG_TO_XLC) {
			sum = chainFinanceTraceImpl.getFirstPrepayAmount(startDate,endDate) + headQCustDaoImpl.selectPbAmount(belongTo2);
		}
		
		fDetailsVO.setBalance(sum);
		fDetailsVOs.add(fDetailsVO);
		if (bills.size() !=0) {
			for (FinanceBill financeBill : bills) {
				HeadqEntityTag entityTag  = headQEntityTagDaoImpl.selectEntityTag(financeBill.getCust().getId(), tagId);
				if (entityTag !=null) {
					FinanceBillFlowDetailsVO fVo = new FinanceBillFlowDetailsVO(financeBill.getId(),
							financeBill.getCust().getName(), FinanceCategory.ACCOUNT_TYPE_NAME_CUST, financeBill.getInvoiceTotal(), 0,
							financeBill.getType(),financeBill.getBillDate(),
							financeBill.getComment(), financeBill.getType(),category);	
					fDetailsVOs.add(fVo);
				}
			}
		}
		
		for (int i = 0; i < fDetailsVOs.size(); i++) {
			if (i == 0) {
				continue;
			}else {
				FinanceBillFlowDetailsVO vo = fDetailsVOs.get(i);
				//预存金充值
				if (vo.getType() == FinanceBill.FINANCE_PREINCOME_HQ) {
					vo.setBalance(sum + vo.getTotal());
					sum += vo.getTotal();
				}else if (vo.getType() == FinanceBill.FINANCE_PREINCOME_SPEND_HQ) {
					vo.setBalance(sum - vo.getTotal());
					sum -= vo.getTotal();
				}
			}
			
		}		
		return fDetailsVOs;
	}

	public List<FinancePrestoreInfoVO> selectPrestoreInfo(FinanceActionFormBean formBean, Date startDate,Date endDate) throws ParseException {
		List<FinancePrestoreInfoVO> list = new ArrayList<FinancePrestoreInfoVO>();
		DetachedCriteria criteria = DetachedCriteria.forClass(FinanceBill.class);
		if (formBean.getHeadQCust().getId() != Common_util.ALL_RECORD) {
			criteria.add(Restrictions.eq("cust.id", formBean.getHeadQCust().getId()));
		}
		criteria.add(Restrictions.or(Restrictions.eq("type", FinanceBill.FINANCE_PREINCOME_HQ), Restrictions.eq("type", FinanceBill.FINANCE_PREINCOME_SPEND_HQ)));
		if (startDate.before(SystemParm.getPrepayFlowDate())) {
			startDate = SystemParm.getPrepayFlowDate();
		}
		//注意：这里的流水只查询完成状态的单据
		criteria.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));
		criteria.add(Restrictions.between("billDate", startDate, endDate));
	
		List<FinanceBill> infos =  getByCritera(criteria, false);
		if (infos.size() != 0) {
			for (FinanceBill bill : infos) {

					FinancePrestoreInfoVO vo = new FinancePrestoreInfoVO();
					vo.setId(Integer.valueOf(bill.getId()));
					vo.setDocumentType(bill.getTypeHQMap().get(bill.getType()));									
					vo.setAmount(bill.getInvoiceTotal());
					vo.setBillDate(Common_util.dateFormat.format(bill.getBillDate()));
					vo.setCustName(bill.getCust().getName());			
					vo.setStatusS(bill.getStatusMap().get(BaseOrder.STATUS_COMPLETE));
					vo.setStatus(BaseOrder.STATUS_COMPLETE);					
					vo.setCreateBy(bill.getCreatorHq().getUser_name());
					vo.setCreateTime(Common_util.dateFormat_f.format(bill.getCreateDate()));
					list.add(vo);
				
			}
		}
		
		return list;
	}

	public List<Integer> getClientIds(HeadQReportFormBean formBean) {
		String sql = "select DISTINCT(cust.id) from FinanceBill s1 where s1.billDate between ? and ? and status = " + BaseOrder.STATUS_COMPLETE;
		// 根据条件补充部分
		List<Object> list = new ArrayList<Object>();
		list.add(Common_util.formStartDate(formBean.getStartDate()));
		list.add(Common_util.formEndDate(formBean.getEndDate()));
		List<Integer> clientIds = new ArrayList<Integer>();
		List<Object> values = this.executeHQLSelect(sql.toString(), list.toArray(), null, true);
		if (values.size() != 0) {
			for (Object record : values) {				
				clientIds.add(Common_util.getInt(record));
			}
		}
		return clientIds;
	}
	
	
	
	/**
	 * 客户往来分析-期中信息赋值(调用）
	 * @param custs
	 * @param formBean
	 * @return
	 * @throws ParseException
	 */
	public List<HeadQDealingsReportDTO> getMidtermInfos(List<HeadQCust> custs, HeadQReportFormBean formBean) throws ParseException {
		List<HeadQDealingsReportDTO> dtos = new ArrayList<HeadQDealingsReportDTO>();
		List<Integer> custIds = new ArrayList<Integer>();
		for (HeadQCust headQCust : custs) {
			custIds.add(headQCust.getId());
		}
		String hql = "SELECT cust.id,type, sum(invoiceTotal) from FinanceBill WHERE cust.id in "+Common_util.parseList2SQLString(custIds)+" AND billDate between ? and ?  and(type = "+FinanceBill.FINANCE_INCOME_HQ+" or type = "+FinanceBill.FINANCE_PREINCOME_HQ+"  or type = "+FinanceBill.FINANCE_PREINCOME_SPEND_HQ+") and status = " + BaseOrder.STATUS_COMPLETE + " group by cust.id,type";
		// 根据条件补充部分
		List<Object> list = new ArrayList<Object>();

		list.add(Common_util.formStartDate(formBean.getStartDate()));
		list.add(Common_util.formEndDate(formBean.getEndDate()));
		List<Object> results = this.executeHQLSelect(hql, list.toArray(),null, true);
		if (results.size() != 0) {
			for (Object record : results) {		
				Object[] ob = (Object[]) record;
				int custId = Common_util.getInt(ob[0]);
				int type = Common_util.getInt(ob[1]);
				double accmt = Common_util.getDouble(ob[2]);
				HeadQDealingsReportDTO dto = new HeadQDealingsReportDTO(custId, type, accmt);
				dtos.add(dto);
			}
		}
        return dtos;
	}

	/**
	 * 客户往来分析-期中信息赋值
	 * @param custs
	 * @param formBean
	 * @param result
	 * @return
	 * @throws ParseException
	 */
	public List<HeadQDealingsReportVO> setMidtermInfo(List<HeadQCust> custs, HeadQReportFormBean formBean,List<HeadQDealingsReportVO> result) throws ParseException {
		List<HeadQDealingsReportDTO> dtos = getMidtermInfos(custs, formBean);
		Map<Integer, HeadQDealingsReportVO> map = new HashMap<Integer, HeadQDealingsReportVO>();
		for (HeadQDealingsReportVO hVo : result) {
			map.put(hVo.getClientId(), hVo);
		}
		for (HeadQDealingsReportDTO headQDealingsReportDTO : dtos) {
			if (map.get(headQDealingsReportDTO.getClientId()) != null) {
				HeadQDealingsReportVO vo = map.get(headQDealingsReportDTO.getClientId());
				if (headQDealingsReportDTO.getType() == FinanceBill.FINANCE_INCOME_HQ) {
					vo.setMidtermPayment(headQDealingsReportDTO.getAmount());
				}else if (headQDealingsReportDTO.getType() == FinanceBill.FINANCE_PREINCOME_HQ) {
					vo.setMidtermRecharge(headQDealingsReportDTO.getAmount());					
				}else if (headQDealingsReportDTO.getType() == FinanceBill.FINANCE_PREINCOME_SPEND_HQ) {
					vo.setMidtermConsumption(headQDealingsReportDTO.getAmount());
				}
				map.put(headQDealingsReportDTO.getClientId(), vo);
			}
		}
		List<HeadQDealingsReportVO> vos = new ArrayList<HeadQDealingsReportVO>();
		for (Integer key:map.keySet()) {
			HeadQDealingsReportVO vo = map.get(key);
			vos.add(vo);
		}		
		return vos;
	}

	/**
	 * 根据时间范围查询单据信息
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public List<FinanceBill> selectBillsByDate(Date startDate, Date endDate,List<Integer> custByTagIds) {
		DetachedCriteria criteria2 = DetachedCriteria.forClass(FinanceBill.class);
		criteria2.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));				 				
		criteria2.add(Restrictions.between("billDate", startDate, endDate));
		if (custByTagIds.size() !=0) {
			criteria2.add(Restrictions.in("cust.id", custByTagIds));
		}
		List<FinanceBill> financeBills = this.getByCritera(criteria2, true);	
		return financeBills;
	}

	/**
	 * 查询时间范围内的客户ID集合
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public List<Integer> selectCIdsByBetweenTime(Date startDate, Date endDate) {
		Set<Integer> set = new HashSet<Integer>();		
		DetachedCriteria criteria2 = DetachedCriteria.forClass(FinanceBill.class);
		criteria2.add(Restrictions.eq("status", FinanceBill.STATUS_COMPLETE));
		startDate = Common_util.formStartDate(startDate);
		endDate = Common_util.formEndDate(endDate);

		criteria2.add(Restrictions.between("billDate", startDate, endDate));
		List<FinanceBill> financeBills = this.getByCritera(criteria2, true);
		if (financeBills.size() !=0) {
			for (FinanceBill financeBill : financeBills) {
				set.add(financeBill.getCust().getId());
			}
		}
		List<Integer> list = new ArrayList<Integer>(set);
		return list;
	}

}
